package eu.silentspycamera;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.hardware.Camera.Size;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.ImageView;
import android.widget.Toast;

import com.admob.android.ads.AdManager;
import com.admob.android.ads.AdView;

import eu.silentspycamera.adabters.AdListener;
import eu.silentspycamera.adabters.ExternalStorageAdabter;
import eu.silentspycamera.menu.Help;
import eu.silentspycamera.menu.Info;
import eu.silentspycamera.menu.PreferenceValues;
import eu.silentspycamera.menu.Preferences;

public class Main extends Activity implements SurfaceHolder.Callback {

	/*
	 * TOUCH SETUP
	 */
	private static final float PERCENTAGE_TO_DRAG = 0.5f; // Percentage of display
													// height to swipe to change
													// opacity completely
	private static final int TAB_TOLERANCE_PX = 15; // Defines width and height of a
											// valid tap. Value is doubled, so
											// e.g. 10 will give a 20 wide tap.
	private static final int MAX_TAP_TIME_MILLISECONDS = 1000; // Maximum length of a
														// tap in milliseconds

	/*
	 * PREFERENCES
	 */
	private SharedPreferences preferences;
	private int opacity; // This is the current opacity
	private boolean toast; // Defines if a toast should be shown on picture taken
	private String toastText; // Text to be displayed on toast

	/*
	 * CAMERA VIEW
	 */
	private SurfaceView surfaceView;
	private SurfaceHolder surfaceHolder;
	private ImageView imgView;
	private Camera camera;
	private boolean previewRunning;
	private int width;
	private int height;

	/*
	 * TOUCH CHANGES
	 */
	private float initY = 0;
	private float initX = 0;
	private float newY = 0;
	private float newX = 0;
	private int originalOpacity = 0;
	private float Yfactor = 0;
	private float Xfactor = 0;
	/*
	 * BACKGROUND PICTURES
	 */
	private List<Bitmap> backgroundPictureList;
	private int backgroundPicture;
	private Boolean NEXT = true;
	private Boolean PREVIOUS = false;
	
	/*
	 * MEDIASOUND CONTROL
	 */
	private int currentVolume;
	private AudioManager mAudioManager;
	
	/*
	 * LOGGING
	 */
	private String TAG = "SSC";
	
	/*
	 * Add
	 */
	private AdView ad;
	
	/*
	 * ExternalStorage 
	 */
	private ExternalStorageAdabter extStor;
	
	
	
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

		extStor = new ExternalStorageAdabter();
		
		backgroundPicture = 0;
		backgroundPictureList = new ArrayList<Bitmap>();
		backgroundPictureList.add(BitmapFactory.decodeResource(getResources(),
				R.drawable.web1));
		backgroundPictureList.add(BitmapFactory.decodeResource(getResources(),
				R.drawable.web2));
		backgroundPictureList.add(BitmapFactory.decodeResource(getResources(),
				R.drawable.screen1));

		loadSharedPreferences();
		initializeSurfaceView();
		initializeImageView();
		setFactor();
		initializeAds(true);
		initializeSound(true);
		 Log.d(TAG, "onCreate'd");
	}


	@Override
	protected void onDestroy() {
		// save all settings
		initializeSound(false);
		initializeAds(false);
		extStor = null;
		super.onDestroy();
	}

	@Override
	protected void onPause() {
		// save all settings
		initializeSound(false);
		//initializeAds(false);
		extStor = null;
		super.onPause(); // this needs to be at the end or we get a nullPointerException when back i pressed
	}

	@Override
	protected void onResume() {
		initializeSound(true);
		initializeAds(true);
		extStor = new ExternalStorageAdabter();
		super.onResume();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.menu, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		Intent intent = null;

		switch (item.getItemId()) {
		case R.id.help:
			intent = new Intent(Main.this, Help.class);
			startActivity(intent);
			return true;
		case R.id.info:
			intent = new Intent(Main.this, Info.class);
			startActivity(intent);
			return true;
		case R.id.preferences:
			intent = new Intent(Main.this, Preferences.class);
			startActivityForResult(intent,
					PreferenceValues.PREFERENCES_REQUEST_CODE);
			return true;
		case R.id.buy:
			intent = new Intent(Intent.ACTION_VIEW,
					Uri.parse("http://www.silentspycamera.eu"));
			startActivity(intent);
			return true;
		default:
			return super.onOptionsItemSelected(item);
		}
	}

	@Override
	public boolean dispatchKeyEvent(KeyEvent event) {
		int action = event.getAction();
		switch (event.getKeyCode()) {
		case KeyEvent.KEYCODE_VOLUME_UP:
		case KeyEvent.KEYCODE_VOLUME_DOWN:
		case KeyEvent.KEYCODE_DPAD_CENTER:
			if (action == KeyEvent.ACTION_UP) {
				takePicture();
			}
			return true;
		default:
			return super.dispatchKeyEvent(event);
		}
		
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {

		case MotionEvent.ACTION_DOWN:
			initY = event.getY();
			initX = event.getX();
			originalOpacity = opacity;
			return true;
		case MotionEvent.ACTION_MOVE:
			// set opasity
			newY = event.getY();
			float y = (initY - newY) * Yfactor;
			opacity = originalOpacity - (int) y;
			if (opacity > 255)
				opacity = 255;
			if (opacity < 1)
				opacity = 0;
			setOpacity(opacity);
			return true;
		case MotionEvent.ACTION_UP:
			long touchDown = event.getDownTime();
			long touchUp = event.getEventTime();
			long downTime = touchUp - touchDown;
			float upX = event.getX();
			float upY = event.getY();
			if ((initX - upX) > -TAB_TOLERANCE_PX
					&& (initX - upX) < TAB_TOLERANCE_PX
					&& (initY - upY) > -TAB_TOLERANCE_PX
					&& (initY - upY) < TAB_TOLERANCE_PX
					&& downTime < MAX_TAP_TIME_MILLISECONDS) {
				takePicture();
			}
			// change background picture
			newX = event.getX();
			float x = (newX - initX);
			if (x > 100 ){ setImageBackground(NEXT); } 
			if(x < -100 ){ setImageBackground(PREVIOUS);}
			return true;
		default:
			return true;
		}
	}

	public void surfaceCreated(SurfaceHolder holder) {
		camera = Camera.open();
		try {
            camera.setPreviewDisplay(holder);
		    } catch (IOException exception) {
		            camera.release();
		            camera = null;
		    }
	}


	public void surfaceDestroyed(SurfaceHolder holder) {
		camera.stopPreview();
		previewRunning = false;
		camera.release();
		camera = null;
	}

	private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
		final double ASPECT_TOLERANCE = 0.05;
		double targetRatio = (double) w / h;
		if (sizes == null)
			return null;

		Size optimalSize = null;
		double minDiff = Double.MAX_VALUE;

		int targetHeight = h;

		// Try to find an size match aspect ratio and size
		for (Size size : sizes) {
			double ratio = (double) size.width / size.height;
			if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
				continue;
			if (Math.abs(size.height - targetHeight) < minDiff) {
				optimalSize = size;
				minDiff = Math.abs(size.height - targetHeight);
			}
		}

		// Cannot find the one match the aspect ratio, ignore the requirement
		if (optimalSize == null) {
			minDiff = Double.MAX_VALUE;
			for (Size size : sizes) {
				if (Math.abs(size.height - targetHeight) < minDiff) {
					optimalSize = size;
					minDiff = Math.abs(size.height - targetHeight);
				}
			}
		}
		return optimalSize;
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
		
		surfaceHolder = holder;
		width = w;
		height = h;	
		initializePreeview();
	}

	private void toast() {
		if (toast) {
			Toast.makeText(imgView.getContext(), toastText, Toast.LENGTH_SHORT)
					.show();
		}
	}

	private void takePicture() {
		if (previewRunning) {
			camera.takePicture(shutterCallback, null, jpegCallback);
			previewRunning = false;
		}
	}

	private void setOpacity(int opacity) {
		BitmapDrawable bmd = new BitmapDrawable(
				((BitmapDrawable) imgView.getBackground()).getBitmap());
		bmd.setAlpha(opacity);
		imgView.setBackgroundDrawable(bmd);
	}

	// if "true" it gets the next picture
	// if "false" the previous picture
	// todo make it work that you can go back and forth in the sequence 
	private BitmapDrawable getNextBackground(boolean nextOrPrevious) {
		if (nextOrPrevious == NEXT){
			backgroundPicture = backgroundPicture + 1;
			if (backgroundPicture > (backgroundPictureList.size() - 1)) {
				backgroundPicture = 0;
			}
		} else {
			backgroundPicture = backgroundPicture - 1;
			if (backgroundPicture < 0) {
				backgroundPicture = backgroundPictureList.size() - 1;
			}
		}
		BitmapDrawable bmd = new BitmapDrawable(
				backgroundPictureList.get(backgroundPicture));
		saveImageBackground(backgroundPicture);
		return bmd;
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		switch (requestCode) {
		case PreferenceValues.PREFERENCES_REQUEST_CODE:
			if (resultCode == RESULT_OK) {
				loadSharedPreferences();
				setOpacity(opacity);
			}
			break;
		default:
		}
	}
	
	/********************
	 * CAMERA CALLBACKS *
	 ********************/
	ShutterCallback shutterCallback = new ShutterCallback() {
		 
		public void onShutter() {
			Log.d(TAG, "onShutter'd");
			toast();
		}
	};

	PictureCallback jpegCallback = new PictureCallback() {

		public void onPictureTaken(byte[] data, Camera camera) {
		
			extStor.SaveImageToFile( data, camera);		
			extStor.insertImageIntoMediaStore(getApplicationContext());
			
			initializePreeview();			
		}
	};

	/**************************
	 * INITIALIZATION METHODS *
	 **************************/
	private void initializePreeview(){
		if (previewRunning)
			camera.stopPreview();

		Camera.Parameters parameters = camera.getParameters();
		parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
		parameters.setRotation(90);
		camera.setDisplayOrientation(90); 


		if (parameters.getSupportedPreviewSizes() != null) {
			List<Size> sizes = parameters.getSupportedPreviewSizes();
			Size optimalSize = getOptimalPreviewSize(sizes, width, height);
			parameters.setPreviewSize(optimalSize.width, optimalSize.height);
		} else {
			parameters.setPreviewSize(width, height);
		}

		camera.setParameters(parameters);
		camera.startPreview();
		previewRunning = true;
	}
	
	private void initializeSurfaceView() {
		surfaceView = (SurfaceView) findViewById(R.id.surface_camera);
		surfaceHolder = surfaceView.getHolder();
		surfaceHolder.addCallback(this);
		surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
	}

	private void initializeImageView() {
		//setImageBackground(true);
		BitmapDrawable bmd = new BitmapDrawable(
				backgroundPictureList.get(backgroundPicture));
		bmd.setGravity(Gravity.FILL);
		bmd.setAlpha(opacity);
		imgView = (ImageView) findViewById(R.id.picview);
		imgView.setBackgroundDrawable(bmd);
	}
	
	private void setImageBackground(boolean nextOrPrevious){
		BitmapDrawable bmd = getNextBackground(nextOrPrevious);
		bmd.setGravity(Gravity.FILL);
		bmd.setAlpha(opacity);
		imgView = (ImageView) findViewById(R.id.picview);
		imgView.setBackgroundDrawable(bmd);
	}

	private void setFactor() {
		Display display = getWindowManager().getDefaultDisplay();
		Yfactor = 255 / ((float) display.getHeight() * PERCENTAGE_TO_DRAG);
	}

	private void loadSharedPreferences() {
		preferences = getSharedPreferences(PreferenceValues.PREFERENCES_FILE,
				MODE_PRIVATE);
		opacity = preferences.getInt(PreferenceValues.OPACITY_KEY,
				PreferenceValues.STANDARD_OPACITY);
		toast = preferences.getBoolean(PreferenceValues.TOAST_ENABLED_KEY,
				PreferenceValues.STANDARD_TOAST_ENABLED);
		toastText = preferences.getString(PreferenceValues.TOAST_TEXT_KEY,
				PreferenceValues.STANDARD_TOAST_TEXT);
		backgroundPicture = preferences.getInt(PreferenceValues.IMAGE_BACKGROUND_KEY,
				PreferenceValues.STANDARD_IMAGE_BACKGROUND);
	}
	
	private void saveImageBackground(int index) {
		SharedPreferences.Editor editor = preferences.edit();
    	editor.putInt(PreferenceValues.IMAGE_BACKGROUND_KEY, index);
    	editor.commit();
	}

	private void initializeAds(boolean enabled) {
		ad = ( AdView ) this.findViewById ( R.id.ad );
		
		/*
		AdManager.setTestDevices ( new String[] {
				 AdManager.TEST_EMULATOR, "SH082PL06653" 
       } );
       if ( AdManager.isTestDevice ( this ) ) {   
             Log.d ( TAG, "we are on a test device" );
       }
		*/
		if (enabled){   
			if ( ad != null && ad.getAdListener() == null) {
				ad.setAdListener ( new AdListener () );
		        Log.d(TAG, "adListener set "); 
		    }
		} else {
			ad.cleanup();
			Log.d(TAG, "ad destroyed: ");
		}
	}
	
	private void initializeSound(boolean enabled){
		if (enabled){
			mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
			currentVolume =  mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
			mAudioManager.setStreamMute(AudioManager.STREAM_SYSTEM, true);
			mAudioManager.setStreamVolume(AudioManager.STREAM_SYSTEM, 0, 0);	
		} else {
		    mAudioManager = (AudioManager) getSystemService(AUDIO_SERVICE);
			mAudioManager.setStreamMute(AudioManager.STREAM_SYSTEM, false);
			mAudioManager.setStreamVolume(AudioManager.STREAM_SYSTEM, currentVolume, 0);	 
			mAudioManager = null;
		}
		
	}
	
	
}